﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dora.Hosts.OAuth.IApplication;
using Dora.Tools.Utility;
using Dora.Tools.Utility.Const;
using Dora.Tools.Utility.Redis;
using Newtonsoft.Json;
using Surging.Core.ApiGateWay.OAuth;
using Surging.Core.Common;
using Surging.Core.CPlatform.Ioc;
using Surging.Core.ProxyGenerator;
using AppConfig = Surging.Core.ApiGateWay.AppConfig;
using Dora.Tools.Utility.Models;
using Surging.Core.CPlatform.Filters.Implementation;
using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration;
using Dora.Tools.Enums;
using Dora.Services.AdminUser.Entities;
using Dora.Tools.Enums.MessageNotice;
using Dora.Core.System;
using Servicecomb.Saga.Omega.Abstractions.Transaction;
using System.Net.Http;

namespace Dora.Hosts.OAuth.Application
{

    [ModuleName(DoraModuleName.OAuthHost)]
    public class OAuthHostService : DoraProxyServiceBase, IOAuthHostService
    {

        public IConfiguration Configuration => AppConfig.Configuration;

        #region 配置项
        private TimeSpan _accessTokenExpireTimeSpan = TimeSpan.FromMinutes(2 * 60);
        public TimeSpan AccessTokenExpireTimeSpan
        {
            get
            {
                if (Configuration["AccessTokenExpireTimeSpan"] != null && int.TryParse(Configuration["AccessTokenExpireTimeSpan"], out int tokenExpireTime))
                {
                    _accessTokenExpireTimeSpan = TimeSpan.FromMinutes(tokenExpireTime);
                }
                return _accessTokenExpireTimeSpan;
            }
            internal set => _accessTokenExpireTimeSpan = value;
        }
        #endregion

        #region url Helper
        private string BuildDoraUserService(string methodName) => $"{DoraServiceRoute.AdminUserRoutePath.IDoraUserService}{methodName}";
        private string BuildTasUserService(string methodName) => $"{DoraServiceRoute.AdminUserRoutePath.ITasUserService}{methodName}";
        private string BuildSrmUserService(string methodName) => $"{DoraServiceRoute.AdminUserRoutePath.ISrmUserService}{methodName}";
        private string BuildPermissionService(string methodName) => $"{DoraServiceRoute.AdminUserRoutePath.IPermissionService}{methodName}";
        public string BuildEasemobService(string methodName) => $"{DoraServiceRoute.MessageNoticeRoutePath.IEasemobService}{methodName}";
        public string BuildSmsService(string methodName) =>
            $"{DoraServiceRoute.MessageNoticeRoutePath.ISmsService}{methodName}";

        /// <summary>
        /// 供应商service地址拼接函数
        /// </summary>
        /// <param name="methodName">方法(Action)Name</param>
        /// <returns></returns>
        public string BuildSupplierService(string methodName) => $"{DoraServiceRoute.SupplierRoutePath.ISupplierService}{methodName}";

        public string BuildUserService(string methodName) => $"{DoraServiceRoute.CustomerUserRoutePath.IUserService}{methodName}";
        public string BuildWxOpenService(string methodName) => $"{DoraServiceRoute.MessageNoticeRoutePath.IWxOpenService}{methodName}";

        public string BuildOrgBigSettingService(string methodName) => $"{DoraServiceRoute.AdminUserRoutePath.IOrgBigSettingService}{methodName}";

        public string BuildOrganizationService(string methodName) => $"{DoraServiceRoute.AdminUserRoutePath.IOrganizationService}{methodName}";
        #endregion

        #region private token method

        private static async Task<ResultDto> CreateToken(IdentityUserDto userDto)
        {
            try
            {                
                var jwtHeader = JsonConvert.SerializeObject(new JWTSecureDataHeader { TimeStamp = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") }); //生成token时间戳                

                var encodedString =
                    $"{ConvertHelper.ConverBase64String(jwtHeader)}.{ConvertHelper.ConverBase64String(userDto.Id.ToString())}"; //连接时间戳和dtunionid

                const string sha256Secret = "sha256"; //读到h256签名私钥
                var signature = ConvertHelper.HMACSHA256(encodedString, sha256Secret); //签名
                var token = $"{encodedString}.{signature}"; //连接时间戳 user info 和签名
                //存token及其它信息
                if (userDto.SystemKey == DoraSysIdentifier.TasMP.ToDescription())
                {
                    await TokenHelper.SaveTokenAsync(userDto.Id.ToString(), token, userDto);
                }
                else
                {
                    await TokenHelper.SaveTokenAsync(userDto.Id.ToString(), token, userDto);
                }
                //Console.WriteLine(@"token已存入redis");
                return ResultDto.Success( token);
            }
            catch (Exception e)
            {
                //TODO 补充错误日志
                Console.WriteLine($@"生成token出错{e.Message}     {e.InnerException}");
                //throw;
                return ResultDto.Error($"生成token出错{e.Message}");
            }
        }
        #endregion

        #region 服务方法
        #region 生成token的方法
        [SagaStart]
        public async Task<ResultDto> GenerateTokenCredential(string userName, string pwd, string systemKey)
        {
            var serviceUrl = "";
            if (systemKey == DoraSysIdentifier.DAS.ToDescription()) { serviceUrl = BuildDoraUserService("login"); }
            if (systemKey == DoraSysIdentifier.SRM.ToDescription()) { serviceUrl = BuildSrmUserService("login"); }
            if (systemKey == DoraSysIdentifier.TAS.ToDescription()) { serviceUrl = BuildTasUserService("login"); }
         

            var ip = ClientIp;
            if (ip == null)
            {
                //TODO 补充ip取不到的日志
                //Console.WriteLine("GenerateTokenCredential ip is null");
                ip = "";
            }
            //TODO 补充日志
            //Console.WriteLine($"GenerateTokenCredential Begin userName:{userName},pwd:{pwd},ip:{ip},systemKey:{systemKey}");

            var httpClient = new HttpClient();
            var userDto = await RemoteInvoke<ResultDto<IdentityUserDto>>(serviceUrl, new { userName, pwd, ip, systemKey }, DoraModuleName.AdminUser);
            Console.WriteLine("事务发起端产生异常");
            throw new Exception("");
            return await GenerateToken(userDto, systemKey);
        }

        /// <summary>
        /// 小程序登录
        /// </summary>
        /// <param name="code"></param>
        /// <param name="avatarUrl"></param>
        /// <param name="nickName"></param>
        /// <param name="gender"></param>
        /// <param name="systemKey"></param>
        /// <returns></returns>
        public async Task<ResultDto> WxOpenLogin(string code, string avatarUrl, string nickName, int gender, int topOrgId, string systemKey)
        {
            var serviceUrl = "";
            var openId = "";
            var session_key = "";
            if (systemKey == DoraSysIdentifier.TasMP.ToDescription())
            {
                string appId = "", appSecret = "";
                serviceUrl = BuildOrgBigSettingService("GetById");
                var orgSetting = await RemoteInvoke<OrgBigSettingEntity>(serviceUrl, new { id = topOrgId }, DoraModuleName.AdminUser);
                if (orgSetting == null)
                {
                    return ResultDto.Error("获取组织机构设置失败");
                    //throw new ArgumentException("获取组织机构设置失败");
                }
                appId = orgSetting.WxMPAppId;
                appSecret = orgSetting.WxMPAppSecret;


                // 小程序通过code获取openid
                serviceUrl = BuildWxOpenService("WXOnLogin");
               
            }
            else
            {
                return ResultDto.Error("未处理的SystemKey");
                //throw new ArgumentException("未处理的SystemKey");
            }
            var ip = ClientIp;
            if (ip == null)
            {
                Console.WriteLine("WxOpenLogin ip is null");
                ip = "";
            }
            //todo 补充日志
            //Console.WriteLine($"WxOpenLogin Begin openId:{openId},topOrgId:{topOrgId},avatarUrl:{avatarUrl},nickName:{nickName},gender:{gender},ip:{ip},systemKey:{systemKey}");
            var userDto = await RemoteInvoke<ResultDto<IdentityUserDto>>(serviceUrl, new { openId, session_key, topOrgId, avatarUrl, nickName, gender, ip = ip, systemKey }, DoraModuleName.CustomerUser);
            if (userDto?.Code == ResultCode.Success)
            {
                if (userDto.Data?.MPUser != null)
                {
                    //userDto.Data.MPUser.WxMPOpenId = openId;
                    //userDto.Data.MPUser.WxSessionKey = session_key;
                    if (userDto.Data.MPUser.BelongOrgId > 0)
                    {
                        var orgInfo = await RemoteInvoke<OrganizationEntity>(BuildOrganizationService("GetById"), new { id = userDto.Data.MPUser.BelongOrgId }, DoraModuleName.AdminUser);
                        if (orgInfo != null)
                        {
                            userDto.Data.MPUser.BelongOrgName = orgInfo.Name;
                        }
                    }
                }
                ////加载旅游顾问的环信用户名
                //serviceUrl = BuildTasUserService("GetById");
                //var userEntity = await RemoteInvoke<TasUserEntity>(serviceUrl, new { id = userDto.Data.MPUser.SaleUserId }, DoraModuleName.AdminUser);
                //if (userEntity != null)
                //{
                //    userDto.Data.MPUser.SaleHxUserName = userEntity.HxUserName;
                //}
            }

            return await GenerateToken(userDto, systemKey);
        }

        /// <summary>
        /// 供应商通过手机号登录之发送短信验证码
        /// </summary>
        /// <param name="mobile"></param>
        /// <returns></returns>
        public async Task<ResultDto> SendLoginVerifyCode(string mobile, string systemKey)
        {
            if (string.IsNullOrWhiteSpace(mobile)) return ResultDto.Error("手机号不能为空!", false);

            if (!VerifyHelper.IsMobilePhone(mobile))
            {
                return ResultDto.Error("请输入正确的手机号");
            }

            var entity = await RemoteInvoke<SrmUserEntity>(BuildSrmUserService("GetByMobile"), new { mobile }, DoraModuleName.AdminUser);
            if (entity == null || entity.IsDeleted == 1 || entity.MobileIsVerified == 0)
            {
                return ResultDto.Error("手机号不存在,请先注册!", false);
            }

            //发送短信验证码
            var result = await SendVerifyCode(entity, mobile, systemKey);
            return result ? ResultDto.Success("发送成功", true) : ResultDto.Error("发送失败", false);
        }

        /// <summary>
        /// 给指定的手机号码发送短信验证码
        /// </summary>
        /// <param name="mobile"></param>
        /// <returns></returns>
        private async Task<bool> SendVerifyCode(SrmUserEntity entity,string mobile, string systemKey)
        {
            var code = GenerateVerifyCode.CreateVerifyCode(mobile);

          
            var result = await RemoteInvoke<bool>(BuildSmsService("SendSms"), new { code }, DoraModuleName.MessageNotice);
            return result;
        }

        /// <summary>
        /// 供应商通过手机号登录之登录
        /// </summary>
        /// <param name="mobile"></param>
        /// <returns></returns>
        public async Task<ResultDto> LoginByMobileAndCode(string mobile, string code, string systemKey)
        {
            if (!VerifyHelper.IsMobilePhone(mobile))
            {
                return ResultDto.Error("请输入正确的手机号");
               //throw new ArgumentException("请输入正确的手机号");
            }
            var vCode = GenerateVerifyCode.GetVerifyCode(mobile);

            if (code != vCode)
            {
                return ResultDto.Error("验证码错误");
                //throw new ArgumentException("验证码错误");
            }

            var serviceUrl = "";
            var openId = "";
            var session_key = "";
            if (systemKey == DoraSysIdentifier.SRM.ToDescription())
            {
                serviceUrl = BuildSrmUserService("LoginByMobile");
            }
            else
            {
                return ResultDto.Error("未处理的SystemKey");
                //throw new ArgumentException("未处理的SystemKey");
            }
            var ip = ClientIp;
            if (ip == null)
            {
                //todo 补充日志
                Console.WriteLine("WxOpenLogin ip is null");
                ip = "";
            }
            //todo 补充日志
            //Console.WriteLine($"WxOpenLogin Begin mobile:{mobile},ip:{ip},systemKey:{systemKey}");
            var userDto = await RemoteInvoke<ResultDto<IdentityUserDto>>(serviceUrl, new { mobile,  ip, systemKey }, DoraModuleName.AdminUser);
            if (userDto?.Code == ResultCode.Success)
            {
            }

            return await GenerateToken(userDto, systemKey);
        }

        private async Task<ResultDto> GenerateToken(ResultDto<IdentityUserDto> userDto,string systemKey)
        {
            if (userDto == null)
            {
                return ResultDto.Error("userDto为null");
                //throw new ArgumentException("userDto为null");
            }

            if (userDto.Code == ResultCode.Success)
            {
                #region 登录后的其它操作
                if (systemKey == DoraSysIdentifier.SRM.ToDescription())
                {
                    if (string.IsNullOrWhiteSpace(userDto.Data.HxUserName))
                    {
                        #region Srm环信注册
                        #endregion
                    }

                    #region 填充Supplier信息
                  
                    #endregion
                }
                else if (systemKey == DoraSysIdentifier.TAS.ToDescription())
                {
                   
                }
                else if (systemKey == DoraSysIdentifier.TasMP.ToDescription())
                {
                }
                #endregion
            }
            else
            {
                return ResultDto.Error(userDto.Msg);
                //throw new ArgumentException(userDto.Msg);
            }
            var token = await CreateToken(userDto.Data);
            return token ;
        }

        #endregion
        public async Task<bool> VerifyPermissions(string authkeyStr, string token)
        {
            if (string.IsNullOrWhiteSpace(authkeyStr)) return true;
            var authKeyArray = authkeyStr.Split(',');
            if (!authKeyArray.Any()) return false;

           // var token = Token;
            if (token == null)
            {
                //todo 补充日志
                Console.WriteLine("VerifyPermissions token is null");
            }
            if (token == "")
            {
                //todo 补充日志
                Console.WriteLine("VerifyPermissions token is empty");
            }

            var userinfo = await TokenHelper.Token2UserInfoAsync(token);
            if (userinfo.IsSuperAdmin == 1) return true;//超管放行 
            var userId = userinfo.Id.ToString();

            List<AuthKeyItem> aukeyList = await TokenHelper.GetAuthKeyAsync(userId);
            if (!aukeyList.Any())
            {
                if (userinfo.SystemKey == DoraSysIdentifier.TAS.ToDescription())
                {
                    aukeyList = await RemoteInvoke<List<AuthKeyItem>>(BuildPermissionService("GetTasAuthKeyList"), new { userId = userinfo.Id, orgId=userinfo.LastOrg.Id }, DoraModuleName.AdminUser);
                }
                else if (userinfo.SystemKey == DoraSysIdentifier.DAS.ToDescription())
                {
                    aukeyList = await RemoteInvoke<List<AuthKeyItem>>(BuildPermissionService("GetDoraAuthKeyList"), new { userId = userinfo.Id }, DoraModuleName.AdminUser);
                }
                else if (userinfo.SystemKey == DoraSysIdentifier.SRM.ToDescription())
                {
                    aukeyList = await RemoteInvoke<List<AuthKeyItem>>(BuildPermissionService("GetSrmAuthKeyList"), new { userId = userinfo.Id }, DoraModuleName.AdminUser);
                }
            }

            await TokenHelper.SetAuthKeyAsync(userId, aukeyList);
            if (aukeyList == null || !aukeyList.Any()) return false;

            foreach (var allkey in aukeyList)
            {
                if (authKeyArray.Contains(allkey.AuthKey)) return true; //有则证明某个key命中
            }
            return false;
        }
        /// <summary>
        /// 验证token合法性
        /// </summary>
        /// <returns></returns>
        public async Task<bool> Validate(string token)
        {
            try
            {
                //var token = Token;
                if (string.IsNullOrWhiteSpace(token))
                {
                    //todo 补充日志
                    Console.WriteLine(@"client token is empty");
                    return false;
                }
                var jwtToken = token.Split('.');
                if (jwtToken.Length != 3)
                {
                    //todo 补充日志
                    Console.WriteLine(@" token 格式错误" + token);
                    return false;
                }

                var userId = await TokenHelper.TokenPart2UserIdAsync(jwtToken[1]);
                var thisToken = await TokenHelper.GetTokenAsync(userId);
                if (string.IsNullOrWhiteSpace(thisToken))
                {
                    //todo 补充日志
                    Console.WriteLine(@"服务器端没有查到token,token key is " + userId);
                    return false;
                }
                if (thisToken != token)
                {
                    //todo 补充日志
                    Console.WriteLine($@"token key=={userId}");
                    Console.WriteLine($@"service token =={thisToken}");
                    Console.WriteLine($@"client token =={token}");
                    return false;
                }
                //刷新一次token,时长为半小时 
                _ = ReFreshToken(userId);
                return true;
            }
            catch (Exception e)
            {
                //todo 补充日志
                Console.WriteLine(e);
            }
            return false;
        }
        /// <inheritdoc />
        /// <summary>
        /// 登出销毁token
        /// </summary>
        /// <returns></returns>
        [DoraAuthorization(AuthKey = "", AuthType = AuthorizationType.JWT)]
        public async Task DestoryClientAuthentication(string token)
        {
            var userId = await TokenHelper.Token2UserIdAsync(token);
            if (!String.IsNullOrEmpty(userId))
            {
                _ = TokenHelper.InvalidTokenAsync(userId);
            }

        }

        /// <summary>
        /// 根据token获取用户Id
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetPayload(string token)
        {
            //return await Task.Run(() => TokenHelper.Token2UserId(Token));
            return await TokenHelper.Token2UserIdAsync(token);
        }
        /// <summary>
        /// 测试接口获取当前时间
        /// </summary>
        /// <returns></returns>
        public Task<DateTime> GetDateTime()
        {
            return Task.FromResult(DateTime.Now);
        }
        /// <summary>
        /// token换用户
        /// </summary>
        /// <returns></returns>
        public async Task<IdentityUserDto> GetUserInfo(string token)
        {
            //var token = Token;
            if (token == null)
            {
                //todo 补充日志
                Console.WriteLine("GetUserInfo token is null");
            }
            if (token == "")
            {
                //todo 补充日志
                Console.WriteLine("GetUserInfo token is empty");
            }
            var userInfo = await TokenHelper.Token2UserInfoAsync(token);
            return userInfo;
        }

        /// <summary>
        /// 刷新token
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        private Task ReFreshToken(string userId)
        {
            return TokenHelper.ReFreshTokenAsync(userId, AccessTokenExpireTimeSpan);
        }
        #endregion


    }
}
